package com.one.blocks.rbac.security;

import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.CreateCache;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.one.blocks.rbac.constant.RbacConstant;
import com.one.blocks.security.authc.AuthenticateService;
import com.one.blocks.security.authc.SubjectSession;
import com.one.blocks.security.config.properties.SecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Instant;
import java.util.UUID;

import static com.one.blocks.rbac.constant.RbacConstant.TokenCache;
import static com.one.blocks.security.constant.SecurityConstant.HEADER_SESSION_ID;

/**
 * @author linfuxin Created on 2022-02-14 14:17:16
 */
@Component
public class AuthenticateServiceImpl implements AuthenticateService {

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private ObjectMapper objectMapper;

    @CreateCache(area = TokenCache.AREA, name = TokenCache.NAME, cacheType = CacheType.BOTH)
    private Cache<String, SubjectSession> tokenCache;

    @Override
    public String resolveSessionId(HttpServletRequest httpRequest) {
        // 移动端获取sessionId
        String sessionId = httpRequest.getHeader(HEADER_SESSION_ID);
        if (sessionId != null) {
            return sessionId;
        }

        // web端获取sessionId
        Cookie[] cookies = httpRequest.getCookies();
        if (cookies == null || cookies.length == 0) {
            return null;
        }
        String cookieName = securityProperties.getCookie().getName();
        for (Cookie cookie : cookies) {
            if (cookieName.equals(cookie.getName())) {
                return cookie.getValue();
            }
        }
        return null;
    }

    @Override
    public SubjectSession loadSession(String sessionId) {
        return tokenCache.get(sessionId);
    }

    @Override
    public void removeSession(String sessionId) {
        tokenCache.remove(sessionId);
    }

    @Override
    public void renewSession(Integer subjectId, HttpServletRequest request, HttpServletResponse response) {

        String sessionId = newSessionId();
        SubjectSession subjectSession = DefaultSubjectSession.builder()
                .subjectId(subjectId)
                .expireTime(Instant.now().plusSeconds(securityProperties.getRefreshSessionSeconds()).toEpochMilli())
                .build();
        tokenCache.put(sessionId, subjectSession);

        // 删除老的sessionId
        // 因为cache是懒加载的，必须第一次用才会真正的创建，所以没法在创建bean时注入cache
        // 加入有多个并发请求过来，删除老的sessionId有可能导致后来的请求token非法，为了简单处理这里不删除老的sessionId
//        String oldSessionId = resolveSessionId(request);
//        if (oldSessionId != null) {
//            globalCacheConfig.getCacheContext().getCache(TokenCache.AREA, TokenCache.NAME).remove(oldSessionId);
//        }
//        if (request.getHeader())
        if (RbacConstant.HEADER_PLATFORM_MINI_APP.equals(request.getHeader(RbacConstant.HEADER_PLATFORM_KEY))) {
            response.setHeader(HEADER_SESSION_ID, sessionId);
        } else {
            writeCookie(sessionId, response);
        }

    }

    private String newSessionId() {
        return UUID.randomUUID().toString();
    }

    private void writeCookie(String sessionId, HttpServletResponse response) {
        SecurityProperties.Cookie cookieProperties = securityProperties.getCookie();
        Cookie cookie = new Cookie(cookieProperties.getName(), sessionId);
        cookie.setHttpOnly(cookieProperties.getHttpOnly());
        cookie.setMaxAge(cookieProperties.getMaxAge());
        cookie.setPath(cookieProperties.getPath());
        response.addCookie(cookie);
    }

}
